require 'rubygems'

module DistributedWorker
  
  # == Overview
  # The server marshals tasks between applications using the Distributed Worker
  # framework and clients willing to participate. Applications send notifications
  # of tasks to the server, which then announces the tasks to clients.
  # Clients may then register for the task with the server at which point
  # the server sends the client a data schema and the task controller.
  # 
  # The server delegates data rows to the clients, and accepts the computed
  # results. Once a minimum number of different clients have computed
  # each data set, the most common result is returned to the application.
  module Server
    
    # == Overview
    # TCP/IP Server giving access to applications to the system
    module JobHandler
      
      # Receive data from an application
      # <distributedworker version="0.1">
      #   <job id="job_uuid" action="announce">
      #     <database user="" password="" server="" table=""/>
      #     <schema>SCHEMA DATAå</schema>
      #     <controller>CONTROLLER DATA</controller>
      #   </job>
      # </distributedworker>
      #
      # <distributedworker>
      #   <job id="job_uuid" action="revoke"/>
      # </distributedworker>
      def receive_data(data)
      end
      
      private
      
      # Setup new job for an application
      # Needs to save database info, controller file and configuration file
      # Needs to also announce job name on a Announcer
      def job_setup(data)
      end
      
      # Teardown a job for an application
      # Take job off a Announcer, clean up database info, data rows, controller & config
      def job_teardown(data)
      end
      
    end
    
    # == Overview
    # Reveive data sets from clients
    module DataSetReceiver
      
      # Receive data from a client
      def receive_data(data)
      end
      
    end
    
    # == Overview
    # Periodicly find completed results and send the most
    # common result for each dataset back to the application.
    #
    # for each job
    # => for each data set
    # =>    if there are job.conf.min.result results for this data set
    # =>      send most common result back to application
    class DataResultMarshaller
    end
    
    # == Overview
    # Periodicly find data sets to be computed and marshal them out to
    # participating client nodes.
    #
    # for each job
    # => find x data sets i haven't computed yet
    # =>  for each data set
    # =>    broadcast it out to x client nodes
    # =>    keep track of which nodes it was sent to... and when
    #
    # for each data set i have computed but is not completed yet
    # => see how long it has been since it was sent out
    # => if it was more then x time ago, send it to more clients if i need to
    class DataProcessMarshaller
            
    end
    
    # == Overview
    # Announce available tasks using mDNS
    class Announcer
      require 'net/dns/resolv-mdns'
      attr_reader :type, :domain, :port, :hash
      
      # Initialize an announcer for a server instance.
      # type: service type
      # domain: domain to post the announcement for
      # port: port service is listening on
      # hash: unknown
      def initialize(type = '_foo._tcp', domain = 'local', port = 9090, hash = {})
        @tasks = Hash.new()
        @type, @domain, @port, @hash = type, domain, port, hash
      end
            
      # announce a task
      def announce(task)
        raise ArgumentError('expected task name') if task.class != String
        unless @tasks.has_key?(task)
          handle = Net::DNS::MDNSSD.register(task, @type, @domain, @port, @hash) { |reply|
            task = reply
            @tasks[task] = handle
          }
        else
          task = nil
        end
        return task
      end
      
      # stop announcing a task
      def revoke(task)
        raise ArgumentError('expected task name') if task.class != String
        @tasks.delete(task).stop() if @tasks.has_key?(task)
      end
      
      # iterate through each task
      def each_task()
        @tasks.each_key { |key| yield @tasks[key] }
      end
      
      # stop announcing all tasks
      def shutdown()
        self.each_task { |task| task.stop() }
        @tasks.clear()
      end
    end
    
  end
  

  
end
